package com.echo.code.thread.aqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * SimpleLock Created by baiyap on 2018/10/10.
 */
public class SimpleLock {

  private final Sync sync = new Sync();

  public static void main(String[] args) {
    SimpleLock mutex = new SimpleLock();
    MyThread t1 = new MyThread("t1", mutex);
    MyThread t2 = new MyThread("t2", mutex);
    MyThread t3 = new MyThread("t3", mutex);
    t1.start();
    t2.start();
    t3.start();
    try {
      t1.join();
      t2.join();
      t3.join();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("main thread exit!");
  }

  public void lock() {
    sync.acquire(1);
  }

  public void unlock() {
    sync.release(1);
  }

  private static class Sync extends AbstractQueuedSynchronizer {

    protected Sync() {
      super();
    }

    @Override
    protected boolean tryAcquire(int ignore) {
      return compareAndSetState(0, 1);
    }

    @Override
    protected boolean tryRelease(int ignore) {
      setState(0);
      return true;
    }
  }

  private static class MyThread extends Thread {

    private SimpleLock lock;

    private MyThread(String name, SimpleLock lock) {
      super(name);
      this.lock = lock;
    }

    @Override
    public void run() {
      try {
        lock.lock();
        System.out.println(getCurrentThreadName() + " get the lock");
        TimeUnit.SECONDS.sleep(2);
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        lock.unlock();
        System.out.println(getCurrentThreadName() + " release the lock");
      }
    }

    private String getCurrentThreadName() {
      return Thread.currentThread().getName();
    }
  }
}
